# -*- coding: utf-8 -*-

import codecs
from copy import deepcopy, copy

from PyQt4 import Qt, QtCore, QtGui

from Ui_MdiWindow import Ui_MdiWindow
from FeMovie import FeMovie
from MovieData import *

# Окно, которое отображает коллекцию.
# Умеет читать/писать в файл, копировать, вставлять и т.д.

class MdiWindow(QtGui.QWidget):

    # Нужно для readonly-mode.
    # Кириллу Владимировичу, правда, такая реализация не очень понравилась.
    def readonly(self):
        return self.__readonly
    def setReadonly(self, value):
        self.__readonly = value
        self.ui.btnAdd.setEnabled(not value)
        self.ui.btnDelete.setEnabled(not value)
        editText = self.readonly() and u"Просмотр" or u"Изменить"
        self.ui.btnEdit.setText(editText)

    def filename(self):
        return self.__filename
    def __setFilename(self, value):
        self.__filename = value
        self.setTitle()

    def modified(self):
        return self.__modified
    def __setModified(self, value):
        self.__modified = value
        self.setTitle()
        self.emit(QtCore.SIGNAL("stateChanged(QWidget*)"), self)
    
    
    def selectionExists(self):
        return len(self.selectedRows()) > 0


    # public slots:
    #
    # stateChanged(QWidget*)


    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.collection = MoviesCollection()
        self.__filename = None
        self.__modified = False
        self.__readonly = False

        self.ui = Ui_MdiWindow()
        self.ui.setupUi(self)

        self.ui.table.setColumnCount(len(Columns))
        for column in Columns:
            self.ui.table.setHorizontalHeaderItem(column.value, QtGui.QTableWidgetItem(column.localName))

        self.ui.table.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.ui.table.horizontalHeader().setDefaultAlignment(Qt.Qt.AlignHCenter)
        self.ui.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)


        self.ui.table.horizontalHeader().resizeSection(Columns.year.value, 70)
        self.ui.table.horizontalHeader().resizeSection(Columns.director.value, 150)


        self.ui.btnEdit.setEnabled(False)
        self.ui.btnDelete.setEnabled(False)


        self.connect(self.ui.btnAdd, QtCore.SIGNAL('clicked()'), self.onAdd)
        self.connect(self.ui.btnEdit, QtCore.SIGNAL('clicked()'), self.onEdit)
        self.connect(self.ui.btnDelete, QtCore.SIGNAL('clicked()'), self.onDelete)
        self.connect(self.ui.table, QtCore.SIGNAL('itemSelectionChanged()'), self.itemSelectionChanged)
        self.connect(self.ui.table, QtCore.SIGNAL('cellDoubleClicked(int, int)'), self.cellDoubleClicked)


    def save(self, filename):
        xmlData = self.collection.serialize()
        with codecs.open(filename, 'wb', 'utf-8') as fs:
            fs.write(xmlData)
        self.__setModified(False)
        self.__setFilename(filename)


    def load(self, filename):
        with codecs.open(filename, 'rb', 'utf-8') as fs:
            xmlData = fs.read()
        self.collection = deserialize(xmlData)
        self.__setModified(False)
        self.__setFilename(filename)
        self.updateScreen()



    def cut(self):
        self.copy()
        self.delete()

    def copy(self):
        xmlData = self.collection.serialize(self.selectedRows())
        QtGui.QApplication.clipboard().setText(xmlData)


    def paste(self):
        xmlData = unicode(QtGui.QApplication.clipboard().text())
        if (xmlData is None) or (len(xmlData) == 0):
            return

        try:
            otherCollection = deserialize(xmlData)
        except:
            QtGui.QMessageBox.critical(self, u'Невозможно добавить фильмы', \
               u'Данные в буфере не являются фильмами.')
            return

        copyCollection = deepcopy(self.collection)
        try:
            copyCollection.merge(otherCollection)
        except (AssertionError), e:
            QtGui.QMessageBox.critical(self, u'Невозможно добавить фильмы', \
                u'%s Удалите этот фильм из текущей коллекции или не пытайтесь его вставить.' % e)
            return

        self.collection = copyCollection

        self.__setModified(True)
        self.updateScreen()


    def delete(self):
        self.onDelete()

    def selectAll(self):
        self.ui.table.selectAll()

    def printDocument(self, printer):
        painter = QtGui.QPainter()
        painter.begin(printer)
        try:
            interMovie = 30
            interPara = 7
            interLine = 0

            fontMainTitle = QtGui.QFont("Sans", 22, 50, False)
            fontTitle = QtGui.QFont("Sans", 18, 50, False)
            fontText = QtGui.QFont("Sans", 12, 30, False)

            freeRect = printer.pageRect()

            def draw(getBoundingRect, drawFunc, inter = 0):
                freeRect.adjust(0, inter, 0, 0)
                rect = getBoundingRect()
                if rect.height() + freeRect.top() > freeRect.bottom():
                    printer.newPage();
                    freeRect.setTopLeft(printer.pageRect().topLeft())
                    freeRect.setBottomRight(printer.pageRect().bottomRight())
                    rect = getBoundingRect()
                drawFunc(rect)
                freeRect.adjust(0, rect.height(), 0, 0)

            def drawText(text, inter = 0, flags=int(Qt.Qt.AlignLeft) | int(Qt.Qt.AlignTop) | int(Qt.Qt.TextWordWrap)):
                draw(lambda: painter.fontMetrics().boundingRect(freeRect, flags, text), \
                    lambda rect: painter.drawText(rect, flags, text),
                    inter)

            def drawPixmap(pixmap, inter = 0):
                draw(lambda:pixmap.rect(), \
                    lambda rect: painter.drawPixmap(freeRect.left(), freeRect.top(), pixmap),
                    inter)


            painter.setFont(fontMainTitle)
            drawText(self.filename(), flags = Qt.Qt.AlignHCenter | Qt.Qt.AlignTop)

            for movie in self.collection.movies:
                painter.setFont(fontTitle)
                drawText(movie.name, interMovie)

                painter.setFont(fontText)
                if movie.director:
                    drawText(u"Режиссер: %s" % movie.director, interPara)
                if movie.year:
                    drawText(u"Год: %s" % movie.year, interPara)
                if movie.actors:
                    drawText(u"В ролях:", interPara)
                    for actor in movie.actors:
                        drawText(u"    %s" % actor)

                if movie.cover:
                    pixmap = QtGui.QPixmap()
                    bytes = Qt.QByteArray(movie.cover)
                    pixmap.loadFromData(Qt.QByteArray(movie.cover))
                    drawPixmap(pixmap, interPara)
                

                if movie.description:
                    textDoc = QtGui.QTextDocument()
                    textDoc.setHtml(movie.description)
                    drawText(u"%s" % textDoc.toPlainText(), interPara)
        finally:
            painter.end()


    # handlers
    def closeEvent(self, event):
        if self.modified():
            res = QtGui.QMessageBox.question(self, u"Коллекция не сохранена", u"Выйти без сохранения?", \
                        QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
            if res == QtGui.QMessageBox.No:
                event.ignore()
                return
        event.accept()


    def onAdd(self):
        feMovie = FeMovie()

        def action():
            self.collection.append(feMovie.movie)
            self.ui.table.setRowCount(len(self.collection.movies))
            self.setRowData(len(self.collection.movies) - 1, feMovie.movie)
            self.__setModified(True)

        feMovie.showAndDo(action, u"Измените хотя бы одно значение.")
        

    def onEdit(self):
        feMovie = FeMovie()
        feMovie.setReadonly(self.readonly())
        curRow = self.ui.table.currentRow()
        feMovie.movie = deepcopy(self.collection.movies[curRow])

        def action():
            self.collection.update(feMovie.movie, curRow)
            self.setRowData(curRow, self.collection.movies[curRow])
            self.__setModified(True)

        feMovie.showAndDo(action, u"Измените хотя бы одно значение.")
        

    def onDelete(self):
        for rowIndex in reversed(self.selectedRows()):
            self.collection.delete(rowIndex)

        self.__setModified(True)
        self.updateScreen()



    def itemSelectionChanged(self):
        selectedCount = len(self.selectedRows())
        self.ui.btnEdit.setEnabled(selectedCount == 1)
        if not self.readonly():
            self.ui.btnDelete.setEnabled(selectedCount > 0)
        self.emit(QtCore.SIGNAL("stateChanged(QWidget*)"), self)

    def cellDoubleClicked(self, row, column):
        self.onEdit()







    # helper functions
    def setRowData(self, rowIndex, movie):
        for column in Columns:
            self.setItemData(rowIndex, column.value, getattr(movie, column.name))

    def setItemData(self, rowIndex, columnIndex, data):
        item = QtGui.QTableWidgetItem()
        item.setData(QtCore.Qt.EditRole, data)
        self.ui.table.setItem(rowIndex, columnIndex, item)

    def selectedRows(self):
        selectedIndexes = [index.row() for index in self.ui.table.selectedIndexes()]
        return list(set(selectedIndexes)) # only unique indexes

    def updateScreen(self):
        movies = self.collection.movies
        self.ui.table.setRowCount(len(movies))
        for i, item in enumerate(movies):
            self.setRowData(i, movies[i])


    def setTitle(self):
        if self.filename() is not None:
            format = u"{0}"
            if self.modified():
                format = u"{0} *"
            self.setWindowTitle(format.format(unicode(self.filename())))


if __name__ == "__main__":
    app = QtGui.QApplication([])

    Options.load()

    dialog = MdiWindow()

    dialog.save("tmp.tmp")
    dialog.load("tmp.tmp")
    
    printer = QtGui.QPrinter()
    printer.setOutputFormat(QtGui.QPrinter.PdfFormat)
    printer.setOutputFileName("out.pdf")
    dialog.printDocument(printer)

    dialog.show()
    app.exec_()
